package com.wqnmdb.im.annotation;

import com.wqnmdb.im.domain.contants.ConstantEnum;
import com.wqnmdb.im.domain.resp.RespUtils;
import com.wqnmdb.im.service.redis.RedisStringService;
import com.wqnmdb.im.utils.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * 重复提交aop
 *
 * @author 李翥
 * @since
 */
@Slf4j
@Aspect
@Order(2)
@Component
public class AvoidRepeatableCommitAspect {

    @Autowired
    private RedisStringService redisStringService;

    @Pointcut("@annotation(com.wqnmdb.im.annotation.AvoidRepeatableCommit)")
    public void reqLock() {}

    /**
     * @param point
     */
    @Around("reqLock()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        //获取注解
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        //目标类、方法
        String className = method.getDeclaringClass().getName();
        String methodName = method.getName();
        Object[] args = point.getArgs();

        //由于使用方法名+用户ID创建的Key，，，必须要有用户id参数
        Object param = args[args.length - 1];
        log.info("防止表单重复提交类：{}. 方法：{}.参数：{}.", className, methodName, param);
        String key = ConstantEnum.REDIS_REQ_LOCK.getContent() + methodName + ":" + param;

        AvoidRepeatableCommit avoidRepeatableCommit = method.getAnnotation(AvoidRepeatableCommit.class);
        long timeout = avoidRepeatableCommit.timeout();
        if (timeout <= 0) {
            //过期时间毫秒
            timeout = 3000;
        }
        //校验该方法该用户的key是否存在，存在直接返回错误
        boolean lock = redisStringService.addStringIfAbsent(key, DateUtil.getNow(), timeout, TimeUnit.MILLISECONDS);
        log.info("创建锁结果:{}. key:{}.", lock, key);
        if(!lock){
            log.error("重复提交,未获取到锁: {}.",key);
            return RespUtils.fail("请勿重复提交");
        }
        //执行方法
        Object object = point.proceed();

        //整理施工现场
        redisStringService.delKey(key);
        log.info("删除锁key:{}.", key);
        return object;
    }
}